package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"strconv"
	"time"

	"github.com/hyperledger/fabric/core/chaincode/shim"
	"github.com/hyperledger/fabric/protos/peer"
)

type simpleChaincode struct {
}

const (
	SupplierKeyPrefix     = "supplier"
	CommpanyKeyPrefix     = "company"
	FinancialOrgKeyPrefix = "financial_org"
	TransactionKeyPrefix  = "transaction"
	TxStatusNew           = "新建（待确认）"
	TxStatusConfirm       = "新建（已确认）"
	TxStatusPayForAnother = "申请代付"
	TxStatusPay           = "已付款（未核实）"
	TxStatusPayed         = "已付款（已核实）"
	TxStatusRefusePay     = "代付被拒"
	TxStatusShip          = "已发货（未核实）"
	TxstatusShiped        = "已发货（已核实）"
	TxStatusRepay         = "已还款（未核实）"
	TxStatusRepayed       = "已还款（已核实）"
)

// 	新建 -> 已确认 -> 申请代付 -> 已付款 ->确认付款-> 已发货 -> 确认发货 -> 已还款 -> 确认已还款
//                       |
//                    拒绝付款 ->回到上一步
type Transaction struct {
	Id                string    `json:"id"`                  // 单号
	Description       string    `json:"description"`         // 备注
	Value             uint64    `json:"value"`               // 金额(单位为一分钱)
	ShipmentNumber    string    `json:"shipment_number"`     // 物流号
	PaymentTxNumber   string    `json:"payment_tx_number"`   // 付款转账号
	RepaymentTxNumber string    `json:"repayment_tx_number"` // 还款转账号
	Status            string    `json:"status"`              // 订单状态      ----请使用上面const中的常量来标记订单状态
	CreateDate        time.Time `json:"create_date"`         // 创建时间
	PaymentDate       time.Time `json:"payment_date"`        // 付款时间
	RepaymentDate     time.Time `json:"repayment_date"`      // 应还款时间
	RepayDate         time.Time `json:"repay_date"`          // 实际还款时间
	Supplier          string    `json:"supplier"`            // 供应商
	Company           string    `json:"company"`             // 采购商
	FinancialOrg      string    `json:"financial_org"`       // 金融机构
}

type Company struct {
	Name           string    `json:"name"`            //企业名
	Phone          string    `json:"phone"`           //联系电话
	Account        string    `json:"account"`         //登录账号
	Password       string    `json:"password"`        //登录密码
	Address        string    `json:"address"`         //地址
	CompanyType    string    `json:"company_type"`    //企业类型，供应商，采购商，金融机构
	EnterpriseCode string    `json:"enterprise_code"` //企业统一社会信用代码
	BankCard       string    `json:"bank_card"`       //银行卡号码
	Balance        uint64    `json:"balance"`         //余额
	CreateDate     time.Time `json:"create_date"`     //创建时间
}

func (s *simpleChaincode) Init(stub shim.ChaincodeStubInterface) peer.Response {
	var err error
	fmt.Println("Init chaincode")
	company := &Company{
		Name:           "HuaWei",
		Phone:          "1234567890",
		Account:        "1001",
		Password:       "123456",
		Address:        "admin",
		CompanyType:    SupplierKeyPrefix,
		EnterpriseCode: "29302391123",
		BankCard:       "1234567890123",
		Balance:        10000,
		CreateDate:     time.Now(),
	}
	marshal, err := json.Marshal(company)
	if err != nil {
		return shim.Error(err.Error())
	}
	resp := createCompany(stub, []string{string(marshal)})
	if resp.Status != 200 {
		return shim.Error(resp.Message)
	}

	company.Name = "ALIYUN"
	company.Account = "1002"
	company.CompanyType = CommpanyKeyPrefix
	company.BankCard = "0987654321123"

	marshal, err = json.Marshal(company)
	if err != nil {
		return shim.Error(err.Error())
	}
	resp = createCompany(stub, []string{string(marshal)})
	if resp.Status != 200 {
		return shim.Error(resp.Message)
	}

	company.Name = "GDGM"
	company.Account = "1003"
	company.CompanyType = FinancialOrgKeyPrefix
	company.BankCard = "56789012345131"

	marshal, err = json.Marshal(company)
	if err != nil {
		return shim.Error(err.Error())
	}
	resp = createCompany(stub, []string{string(marshal)})
	if resp.Status != 200 {
		return shim.Error(resp.Message)
	}

	fmt.Println("Inited chiancode")
	return shim.Success(nil)
}

func (s *simpleChaincode) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
	function, args := stub.GetFunctionAndParameters()

	switch function {
	case "newTransaction":
		return newTransaction(stub, args)
	case "createCompany":
		return createCompany(stub, args)
	case "confirmTransaction":
		return confirmTransaction(stub, args)
	case "applyPayForAnother":
		return applyPayForAnother(stub, args)
	case "payTransaction":
		return payTransaction(stub, args)
	case "affirmPay":
		return affirmPay(stub, args)
	case "refusePayTransaction":
		return refusePayTransaction(stub, args)
	case "updateShipmentInfo":
		return updateShipmentInfo(stub, args)
	case "verifyShipmentInfo":
		return verifyShipmentInfo(stub, args)
	case "repayTransaction":
		return repayTransaction(stub, args)
	case "verifyRepay":
		return verifyRepay(stub, args)
	case "autoRepay":
		return autoRepay(stub, args)
	case "getCompany":
		return getCompany(stub, args)
	case "getTrByBuyer":
		return getTrByBuyer(stub, args)
	case "getTransactions":
		return getTransactions(stub, args)
	case "getTransactionHistory":
		return getTransactionHistory(stub, args)
	default:
		return shim.Error("function name is error")
	}

}

/*
	- create new Transaction
	@Param: {id:string, Value:int, supplier:string, create_date:time.Time, company:string}
*/
func newTransaction(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数错误")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Value == 0 || transaction.Supplier == "" || transaction.CreateDate.IsZero() || transaction.Company == "" {
		return shim.Error("入参不能为空" + " " + transaction.Id + " " + fmt.Sprintf("%d", transaction.Value) + " " + transaction.Supplier + transaction.CreateDate.String() + transaction.Company)
	}

	supplierKey, err := stub.CreateCompositeKey(SupplierKeyPrefix, []string{transaction.Supplier})
	if err != nil {
		return shim.Error(err.Error())
	}
	supplierByte, err := stub.GetState(supplierKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(supplierByte) == 0 {
		return shim.Error("supplier org not found")
	}

	companyKey, err := stub.CreateCompositeKey(CommpanyKeyPrefix, []string{transaction.Company})
	if err != nil {
		return shim.Error(err.Error())
	}
	companyByte, err := stub.GetState(companyKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(companyByte) == 0 {
		return shim.Error("company org not found")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}

	transaction.Status = TxStatusNew
	transactionByte, err := json.Marshal(transaction)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*
	- 创建三种不同类型的企业  company、supplier、financialorg
	@Param:  Company
*/
func createCompany(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("args number is error - by createCompany")
	}

	company := new(Company)
	if err = json.Unmarshal([]byte(args[0]), company); err != nil {
		return shim.Error(err.Error())
	}

	if company.Name == "" || company.CreateDate.IsZero() || company.Account == "" || company.Address == "" || company.BankCard == "" || company.CompanyType == "" || company.EnterpriseCode == "" || company.Password == "" || company.Phone == "" {
		return shim.Error("args cound not is null")
	}

	key, err := stub.CreateCompositeKey(company.CompanyType, []string{company.Account})
	if err != nil {
		return shim.Error(err.Error())
	}

	companyByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(companyByte) != 0 {
		return shim.Error("该帐号已存在")
	}

	companyByte, err = json.Marshal(company)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, companyByte); err != nil {
		return shim.Error(err.Error())
	}
	return shim.Success(nil)
}

/*
	- 确认订单
	@Param: {id:string, supplier:string}
*/
func confirmTransaction(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("args length is not one")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Supplier == "" {
		return shim.Error(err.Error())
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}
	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}

	transactionUpdate := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdate); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdate.Supplier != transaction.Supplier {
		return shim.Error("supplier is error")
	}

	transaction.Status = TxStatusConfirm

	transactionByte, err = json.Marshal(transaction)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 向金融机构申请代付
	@Param: {id:string, company:string, financial_org:string, repayment_date:time.Time}
*/
func applyPayForAnother(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Company == "" || transaction.FinancialOrg == "" || transaction.RepaymentDate.IsZero() {
		return shim.Error("入参不能为空")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}

	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.Company != transaction.Company {
		return shim.Error("company is error")
	}

	finanicalKey, err := stub.CreateCompositeKey(FinancialOrgKeyPrefix, []string{transaction.FinancialOrg})
	if err != nil {
		return shim.Error(err.Error())
	}
	finanicalByte, err := stub.GetState(finanicalKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(finanicalByte) == 0 {
		return shim.Error("finanical is not found")
	}

	transactionUpdata.Status = TxStatusPayForAnother
	transactionUpdata.FinancialOrg = transaction.FinancialOrg
	transactionUpdata.RepaymentDate = transaction.RepaymentDate

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 付款
	@Paramm: {id:string,PaymentTxNumber:string,financial_org:string,payment_date:time.Time}
*/
func payTransaction(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error(err.Error())
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.PaymentTxNumber == "" || transaction.FinancialOrg == "" || transaction.PaymentDate.IsZero() {
		return shim.Error("入参不能为空" + transaction.Id + " " + transaction.PaymentTxNumber + " " + transaction.FinancialOrg + " " + transaction.PaymentDate.String())
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}
	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}
	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.FinancialOrg != transaction.FinancialOrg {
		return shim.Error("financialorg is error")
	}

	// 获取金融商账户信息
	financialKey, err := stub.CreateCompositeKey(FinancialOrgKeyPrefix, []string{transactionUpdata.FinancialOrg})
	if err != nil {
		return shim.Error(err.Error())
	}
	financialByte, err := stub.GetState(financialKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	financial := new(Company) // 金融商账户信息
	if err = json.Unmarshal(financialByte, financial); err != nil {
		return shim.Error(err.Error())
	}

	// 获取供应商账户信息
	supplierKey, err := stub.CreateCompositeKey(SupplierKeyPrefix, []string{transactionUpdata.Supplier})
	if err != nil {
		return shim.Error(err.Error())
	}
	supplierByte, err := stub.GetState(supplierKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	supplier := new(Company) // 供应商账户信息
	if err = json.Unmarshal(supplierByte, supplier); err != nil {
		return shim.Error(err.Error())
	}

	// 转账
	financial.Balance -= transactionUpdata.Value
	supplier.Balance += transaction.Value

	financialByte, err = json.Marshal(financial)
	if err != nil {
		return shim.Error(err.Error())
	}
	supplierByte, err = json.Marshal(supplier)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(financialKey, financialByte); err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(supplierKey, supplierByte); err != nil {
		return shim.Error(err.Error())
	}

	transactionUpdata.Status = TxStatusPay
	transactionUpdata.PaymentDate = transaction.PaymentDate

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 供应商核实付款
	@Param: {id:string, supplier:string}
*/
func affirmPay(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error(err.Error())
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Supplier == "" {
		return shim.Error(err.Error())
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}

	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.Supplier != transaction.Supplier {
		return shim.Error("supplier is error")
	}

	transactionUpdata.Status = TxStatusPayed

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 拒绝付款要求
	@Param: {id:string,description:string,financial_org:string}
*/
func refusePayTransaction(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Description == "" || transaction.FinancialOrg == "" {
		return shim.Error("入参不能为空")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}
	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.FinancialOrg != transaction.FinancialOrg {
		return shim.Error("finacialorg is error")
	}

	transactionUpdata.Status = TxStatusRefusePay
	transactionUpdata.Description = transaction.Description

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 供应商发货
	@Param: {id:string,shipment_number:string,supplier:string}
*/
func updateShipmentInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error(err.Error())
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.ShipmentNumber == "" || transaction.Supplier == "" {
		return shim.Error(err.Error())
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}
	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.Supplier != transaction.Supplier {
		return shim.Error("supplier is error")
	}

	transactionUpdata.Status = TxStatusShip
	transactionUpdata.ShipmentNumber = transaction.ShipmentNumber

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 买方收获
	@Param: {id:string,company:string}
*/
func verifyShipmentInfo(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.Company == "" {
		return shim.Error("入参不能为空")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}

	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("该交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.Company != transaction.Company {
		return shim.Error("company is error")
	}

	transactionUpdata.Status = TxstatusShiped
	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 买方还款
	@Param:{id:string,repayment_tx_number:string,tx_to_update:time.Time,company:string}
*/
func repayTransaction(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error(err.Error())
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.RepaymentTxNumber == "" || transaction.Company == "" || transaction.RepayDate.IsZero() {
		return shim.Error("入参不能为空")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}
	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	if len(transactionByte) == 0 {
		return shim.Error("交易信息不存在")
	}
	transactionUpdate := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdate); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdate.Company != transaction.Company {
		return shim.Error("company is error")
	}

	// 获取买方账户信息
	companyKey, err := stub.CreateCompositeKey(CommpanyKeyPrefix, []string{transactionUpdate.Company})
	if err != nil {
		return shim.Error(err.Error())
	}

	companyByte, err := stub.GetState(companyKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	company := new(Company) // 买方账户信息
	if err = json.Unmarshal(companyByte, company); err != nil {
		return shim.Error(err.Error())
	}

	// 获取金融商账户信息
	financialKey, err := stub.CreateCompositeKey(FinancialOrgKeyPrefix, []string{transactionUpdate.FinancialOrg})
	if err != nil {
		return shim.Error(err.Error())
	}

	financialByte, err := stub.GetState(financialKey)
	if err != nil {
		return shim.Error(err.Error())
	}
	financial := new(Company) // 金融商账户信息
	if err = json.Unmarshal(financialByte, financial); err != nil {
		return shim.Error(err.Error())
	}

	// 转账
	company.Balance -= transactionUpdate.Value
	financial.Balance += transactionUpdate.Value

	companyByte, err = json.Marshal(company)
	if err != nil {
		return shim.Error(err.Error())
	}
	financialByte, err = json.Marshal(financial)
	if err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(companyKey, companyByte); err != nil {
		return shim.Error(err.Error())
	}
	if err = stub.PutState(financialKey, financialByte); err != nil {
		return shim.Error(err.Error())
	}

	transactionUpdate.Status = TxStatusRepay
	transactionUpdate.RepaymentTxNumber = transaction.RepaymentTxNumber
	transactionUpdate.RepayDate = transaction.RepayDate

	transactionByte, err = json.Marshal(transactionUpdate)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 确认还款
	@Param:  {id:string,financial_org:string}
*/
func verifyRepay(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("args number is error")
	}

	transaction := new(Transaction)
	if err = json.Unmarshal([]byte(args[0]), transaction); err != nil {
		return shim.Error(err.Error())
	}

	if transaction.Id == "" || transaction.FinancialOrg == "" {
		return shim.Error("args is null")
	}

	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{transaction.Id})
	if err != nil {
		return shim.Error(err.Error())
	}

	transactionByte, err := stub.GetState(key)
	if err != nil {
		return shim.Error(err.Error())
	}

	if len(transactionByte) == 0 {
		return shim.Error("交易信息不存在")
	}

	transactionUpdata := new(Transaction)
	if err = json.Unmarshal(transactionByte, transactionUpdata); err != nil {
		return shim.Error(err.Error())
	}

	if transactionUpdata.FinancialOrg != transaction.FinancialOrg {
		return shim.Error("financial org is error")
	}

	transactionUpdata.Status = TxStatusRepayed

	transactionByte, err = json.Marshal(transactionUpdata)
	if err != nil {
		return shim.Error(err.Error())
	}

	if err = stub.PutState(key, transactionByte); err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(nil)
}

/*
	- 自动还款
	@Param: nowTime:time.Time
*/

func autoRepay(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	nowTime, err := time.Parse("2006-01-02 15:04:05", args[0])
	if err != nil {
		return shim.Error(err.Error())
	}

	if nowTime.IsZero() {
		return shim.Error("入参不能为空")
	}

	it, err := stub.GetStateByPartialCompositeKey(TransactionKeyPrefix, []string{})
	if err != nil {
		return shim.Error(err.Error())
	}

	defer it.Close()
	for it.HasNext() {
		val, err := it.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		transaction := new(Transaction)
		if err = json.Unmarshal(val.GetValue(), transaction); err != nil {
			return shim.Error(err.Error())
		}

		if transaction.RepaymentDate.Unix() < nowTime.Unix() {
			if !(transaction.Status == TxStatusRepayed) || !(transaction.Status == TxStatusRepay) {
				// {id:string,repayment_tx_number:string,tx_to_update:time.Time,company:string}

				companyKey, err := stub.CreateCompositeKey(CommpanyKeyPrefix, []string{transaction.Company})
				if err != nil {
					return shim.Error(err.Error())
				}
				companyByte, err := stub.GetState(companyKey)
				if err != nil {
					return shim.Error(err.Error())
				}
				company := new(Company)
				if err = json.Unmarshal(companyByte, company); err != nil {
					return shim.Error(err.Error())
				}
				transaction.RepaymentTxNumber = company.BankCard

				transaction.RepayDate = nowTime

				transactionByte, err := json.Marshal(transaction)
				if err != nil {
					return shim.Error(err.Error())
				}
				resp := repayTransaction(stub, []string{string(transactionByte)})
				if resp.Status != 200 {
					return shim.Error(resp.Message)
				}
			}
		}

	}
	return shim.Success(nil)
}

/*
	- 根据企业类型获取企业信息
	@Param:  companyType:string 企业类型
*/
func getCompany(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	companyType := args[0]
	if companyType == "" {
		return shim.Error("入参不能为空")
	}

	it, err := stub.GetStateByPartialCompositeKey(companyType, []string{})
	if err != nil {
		return shim.Error(err.Error())
	}
	var companys []*Company
	defer it.Close()
	for it.HasNext() {
		val, err := it.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		company := new(Company)
		if err = json.Unmarshal(val.GetValue(), company); err != nil {
			return shim.Error(err.Error())
		}
		companys = append(companys, company)
	}

	companysByte, err := json.Marshal(companys)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(companysByte)
}

/*
	@Param:  buyer:string 买方公司名
	@Return: {transactions:[]Transaction,unfinished:int,total:int,violateTreaty:int}
			分别为此买方的交易信息、未完成交易数、交易总数、违约交易数（实际还款时间RepayDate大于应还款时间RepaymentDate）
*/
func getTrByBuyer(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error("入参个数应等于1")
	}

	buyer := args[0]
	if buyer == "" {
		return shim.Error("入参不能为空")
	}

	it, err := stub.GetStateByPartialCompositeKey(TransactionKeyPrefix, []string{})
	if err != nil {
		return shim.Error(err.Error())
	}
	var transactions []Transaction
	var unfinished int64
	var total int64
	var violateTreaty int64
	defer it.Close()
	for it.HasNext() {
		val, err := it.Next()
		if err != nil {
			return shim.Error(err.Error())
		}

		var transaction Transaction
		if err = json.Unmarshal(val.GetValue(), &transaction); err != nil {
			return shim.Error(err.Error())
		}

		if transaction.Company != buyer {
			continue
		}
		transactions = append(transactions, transaction)
		total++

		if !(transaction.Status == TxStatusRepayed) || !(transaction.Status == TxStatusRepay) {
			unfinished++
			if transaction.RepaymentDate.Unix() < time.Now().Unix() {
				violateTreaty++
			}

		}
		if transaction.RepaymentDate.Unix() < transaction.RepayDate.Unix() {
			violateTreaty++
		}
	}
	data := make(map[string]interface{}, 0)
	data["transactions"] = transactions
	data["total"] = total
	data["unfinished"] = unfinished
	data["violateTreaty"] = violateTreaty

	dataByte, err := json.Marshal(data)
	if err != nil {
		return shim.Error(err.Error())
	}

	return shim.Success(dataByte)

}

/*
	- 获取交易信息  不传交易id进函数，则查询所言交易信息
	@Param:  [id0,id1] []string
*/
func getTransactions(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) > 1 {
		return shim.Error("入参个数应小于或等于1")
	}

	var keys []string

	if len(args) == 1 {
		if err = json.Unmarshal([]byte(args[0]), &keys); err != nil {
			return shim.Error(err.Error())
		}
	}

	if len(keys) == 0 {
		it, err := stub.GetStateByPartialCompositeKey(TransactionKeyPrefix, keys)
		if err != nil {
			return shim.Error(err.Error())
		}
		var transactions []Transaction
		defer it.Close()
		for it.HasNext() {
			val, err := it.Next()
			if err != nil {
				return shim.Error(err.Error())
			}

			var transaction Transaction

			if err = json.Unmarshal(val.GetValue(), &transaction); err != nil {
				return shim.Error(err.Error())
			}

			transactions = append(transactions, transaction)

		}

		transactionsByte, err := json.Marshal(transactions)
		if err != nil {
			return shim.Error(err.Error())
		}
		return shim.Success(transactionsByte)
	} else {
		var transactions []Transaction
		for _, k := range keys {
			key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{k})
			if err != nil {
				return shim.Error(err.Error())
			}
			transactionByte, err := stub.GetState(key)
			if err != nil {
				return shim.Error(err.Error())
			}
			if len(transactionByte) == 0 {
				continue
			}
			var transaction Transaction
			if err = json.Unmarshal(transactionByte, &transaction); err != nil {
				return shim.Error(err.Error())
			}
			transactions = append(transactions, transaction)
		}
		transactionsByte, err := json.Marshal(transactions)
		if err != nil {
			return shim.Error(err.Error())
		}
		return shim.Success(transactionsByte)
	}

}

/*
	- 查询交易历史记录
	@Param: id:string
*/
func getTransactionHistory(stub shim.ChaincodeStubInterface, args []string) peer.Response {
	var err error
	if len(args) != 1 {
		return shim.Error(err.Error())
	}

	id := args[0]

	if id == "" {
		return shim.Error("入参不能为空")
	}
	key, err := stub.CreateCompositeKey(TransactionKeyPrefix, []string{id})
	if err != nil {
		return shim.Error(err.Error())
	}
	it, err := stub.GetHistoryForKey(key)
	if err != nil {
		return shim.Error(err.Error())
	}
	var buf bytes.Buffer
	pd := false
	defer it.Close()
	buf.WriteString("[")
	for it.HasNext() {
		val, err := it.Next()
		if err != nil {
			return shim.Error(err.Error())
		}
		if pd {
			buf.WriteString(",")
		}
		buf.WriteString("{")

		buf.WriteString("\"TxId\":")
		buf.WriteString("\"")
		buf.WriteString(val.TxId)
		buf.WriteString("\"")
		buf.WriteString(",")

		buf.WriteString("\"Value\":")
		if val.GetIsDelete() {
			buf.WriteString("null")
		} else {
			buf.WriteString(string(val.GetValue()))
		}
		buf.WriteString(",")

		buf.WriteString("\"Timestamp\":")
		buf.WriteString("\"")
		buf.WriteString(val.Timestamp.String())
		buf.WriteString("\"")
		buf.WriteString(",")

		buf.WriteString("\"IsDelete\":")
		buf.WriteString("\"")
		buf.WriteString(strconv.FormatBool(val.IsDelete))
		buf.WriteString("\"")
		buf.WriteString("}")
		pd = true
	}
	buf.WriteString("]")

	return shim.Success(buf.Bytes())
}

func main() {
	err := shim.Start(new(simpleChaincode))
	if err != nil {
		panic(err.Error())
	}
}
